package com.ms.orm.conditions.query;

import com.ms.common.util.ArrayUtils;
import com.ms.common.util.Assert;
import com.ms.common.util.StringUtils;
import com.ms.orm.conditions.AbstractLambdaWrapper;
import com.ms.orm.conditions.SharedString;
import com.ms.orm.conditions.segments.MergeSegments;
import com.ms.orm.constants.Constants;
import com.ms.orm.meta.PropertyAndColumnInfo;
import com.ms.orm.util.MetaDataOperator;
import com.ms.orm.util.support.SFunction;

import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;

/**
 * Lambda 语法使用 Wrapper
 */
@SuppressWarnings("serial")
public class LambdaQueryWrapper<T> extends AbstractLambdaWrapper<T, LambdaQueryWrapper<T>> implements Query<LambdaQueryWrapper<T>, T, SFunction<T, ?>> {


    /**
     * 查询字段
     */
    private SharedString sqlSelect = new SharedString();

    public LambdaQueryWrapper() {
        this((T) null);
    }

    public LambdaQueryWrapper(T entity) {
        super.setEntity(entity);
        super.initNeed();
    }

    public LambdaQueryWrapper(Class<T> entityClass) {
        super.setEntityClass(entityClass);
        super.initNeed();
    }

    LambdaQueryWrapper(T entity, Class<T> entityClass, SharedString sqlSelect, AtomicInteger paramNameSeq,
                       Map<String, Object> paramNameValuePairs, MergeSegments mergeSegments, SharedString paramAlias,
                       SharedString lastSql, SharedString sqlComment, SharedString sqlFirst) {
        super.setEntity(entity);
        super.setEntityClass(entityClass);
        this.paramNameSeq = paramNameSeq;
        this.paramNameValuePairs = paramNameValuePairs;
        this.expression = mergeSegments;
        this.sqlSelect = sqlSelect;
        this.paramAlias = paramAlias;
        this.lastSql = lastSql;
        this.sqlComment = sqlComment;
        this.sqlFirst = sqlFirst;
        this.paramNameValue = new ArrayList<>();
    }

    /**
     * SELECT 部分 SQL 设置
     *
     * @param columns 查询字段
     */
    @SafeVarargs
    @Override
    public final LambdaQueryWrapper<T> select(SFunction<T, ?>... columns) {
        if (ArrayUtils.hasElement(columns)) {
            this.sqlSelect.setStringValue(columnsToString(false, columns));
        }
        return typedThis;
    }

    /**
     * 过滤查询的字段信息(主键除外!)
     * <p>例1: 只要 java 字段名以 "test" 开头的             -> select(i -&gt; i.getProperty().startsWith("test"))</p>
     * <p>例2: 只要 java 字段属性是 CharSequence 类型的     -> select(TableFieldInfo::isCharSequence)</p>
     * <p>例3: 只要 java 字段没有填充策略的                 -> select(i -&gt; i.getFieldFill() == FieldFill.DEFAULT)</p>
     * <p>例4: 要全部字段                                   -> select(i -&gt; true)</p>
     * <p>例5: 只要主键字段                                 -> select(i -&gt; false)</p>
     *
     * @param predicate 过滤方式
     * @return this
     */
    @Override
    public LambdaQueryWrapper<T> select(Class<T> entityClass, Predicate<PropertyAndColumnInfo> predicate) {
        if (entityClass == null) {
            entityClass = getEntityClass();
        } else {
            setEntityClass(entityClass);
        }
        Assert.notNull(entityClass, "entityClass can not be null");
        this.sqlSelect.setStringValue(MetaDataOperator.getEntityAndTableInfo(entityClass).chooseSelect(predicate));
        return typedThis;
    }

    @Override
    public String getSqlSelect() {
        return sqlSelect.getStringValue();
    }

    /**
     * 用于生成嵌套 sql
     * <p>故 sqlSelect 不向下传递</p>
     */
    @Override
    protected LambdaQueryWrapper<T> instance() {
        return new LambdaQueryWrapper<>(getEntity(), getEntityClass(), null, paramNameSeq, paramNameValuePairs,
                new MergeSegments(), paramAlias, SharedString.emptyString(), SharedString.emptyString(), SharedString.emptyString());
    }

    @Override
    public void clear() {
        super.clear();
        sqlSelect.toNull();
    }

    /**
     * 获取查询语句
     * @return
     */
    @Override
    public String getFinalSql() {
        StringBuilder builder = new StringBuilder();
        //1、有查询条件，拼接 SELECT
        builder.append(Constants.SELECT).append(Constants.SPACE);
        if(StringUtils.hasLength(this.getSqlSelect())){
            //2、有查询条件，拼接 查询字段,指定查询字段
            builder.append(this.getSqlSelect()).append(Constants.SPACE);
        }else{
            builder.append(MetaDataOperator.getEntityAndTableInfo(getEntityClass()).getAllSqlSelect()).append(Constants.SPACE);
        }
        builder.append(Constants.FROM).append(Constants.SPACE).append(MetaDataOperator.getEntityAndTableInfo(getEntityClass()).getTableName()).append(Constants.SPACE);

        //3、有查询条件，拼接 WHERE
        if(!this.getExpression().getNormal().isEmpty()){
            builder.append(Constants.WHERE).append(Constants.SPACE);
        }
        if(StringUtils.hasLength(this.getExpression().getSqlSegment())){
            builder.append(this.getExpression().getSqlSegment());
        }
        return builder.toString();
    }

}